/**
  ******************************************************************************
  * @file OptimizedI2Cexamples/src/I2CRoutines.c
  * @author  MCD Application Team
  * @version  V4.0.0
  * @date  06/18/2010
  * @brief  Contains the I2Cx slave/Master read and write routines.
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2010 STMicroelectronics</center></h2>
  */

/* Includes ------------------------------------------------------------------*/
#include "includes.h"
#include <stm32f10x_dma.h>
#include "I2CRoutines.h"
#include "MyRtos.h"
#include "apptimer.h"

#define  I2C2_TMO         0x100

#define  I2C_POLLING_MODE     0
#define  I2C_INTERRUPT_MODE   1
#define  I2C_DMA_MODE         2

#define  I2C_MODE             I2C_POLLING_MODE

/** @addtogroup Optimized I2C examples
  * @{
  */


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
DMA_InitTypeDef  I2CDMA_InitStructure;
__IO uint32_t I2CDirection = I2C_DIRECTION_TX;
__IO uint32_t NumbOfBytes1;
__IO uint32_t NumbOfBytes2;
__IO uint8_t Address;
static Boolean _I2C_NotUsed;
static void ForecStop(void);
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Reads buffer of bytes  from the slave.
  * @param pBuffer: Buffer of bytes to be read from the slave.
  * @param NumByteToRead: Number of bytes to be read by the Master.
  * @param Mode: Polling or DMA or Interrupt having the highest priority in the application.
  * @param SlaveAddress: The address of the slave to be addressed by the Master.
  * @retval : None.
  */
/*************************************************************************
 * Function Name: I2C2_Open
 * Parameters: none
 *
 * Return: Boolean
 *
 * Description: Init I2C2 interface open
 *
 *************************************************************************/
Boolean I2C2_Open (void)
{
  return(0 != AtomicExchange(FALSE, &_I2C_NotUsed));
}

/*************************************************************************
 * Function Name: I2C2_Close
 * Parameters: none
 *
 * Return: none
 *
 * Description: Init I2C2 interface release
 *
 *************************************************************************/
void I2C2_Close (void)
{
  AtomicExchange(TRUE, &_I2C_NotUsed);
}


#if  I2C_MODE == I2C_DMA_MODE

Status I2C2_Master_BufferRead(uint8_t* pBuffer,  uint32_t NumByteToRead, uint8_t SlaveAddress)
{
  if(I2C2_Master_BufferRead_Init(pBuffer,NumByteToRead,SlaveAddress)!= Success) return Error;
  while(!I2C2_RxDone()) Yield();
  return Success;
}

Status I2C2_Master_BufferRead_Init(uint8_t* pBuffer,  uint32_t NumByteToRead, uint8_t SlaveAddress)

{
    __IO uint32_t temp = 0;
    __IO uint32_t Timeout = 0;

    /* Enable I2C errors interrupts (used in all modes: Polling, DMA and Interrupts */
    I2C2->CR2 |= I2C_IT_ERR;

        /* Configure I2Cx DMA channel */
        I2C2_DMAConfig(pBuffer, NumByteToRead, I2C_DIRECTION_RX);
        /* Set Last bit to have a NACK on the last received byte */
        I2C2->CR2 |= CR2_LAST_Set;
        /* Enable I2C DMA requests */
        I2C2->CR2 |= CR2_DMAEN_Set;
        Timeout = I2C2_TMO;
        /* Send START condition */
        I2C2->CR1 |= CR1_START_Set;
        /* Wait until SB flag is set: EV5  */
        while ((I2C2->SR1&0x0001) != 0x0001)
        {
          if (Timeout-- == 0){
                ForecStop();
                return Error;
          }
        }
        Timeout = I2C2_TMO;
        /* Send slave address */
        /* Set the address bit0 for read */
        //SlaveAddress |= OAR1_ADD0_Set;
        Address = (SlaveAddress<<1)|OAR1_ADD0_Set;
        /* Send the slave address */
        I2C2->DR = Address;
        /* Wait until ADDR is set: EV6 */
        while ((I2C2->SR1&0x0002) != 0x0002)
        {
           if((I2C2->SR1 & (1<<10))||(Timeout-- == 0)){
              I2C2->SR1 &= ~(1<<10);
              ForecStop();
              return Error;
           }
        }
        /* Clear ADDR flag by reading SR2 register */
        temp = I2C2->SR2;
    return Success;
}

static void ForecStop(void)
{
  /* Disable DMA Channel */
  DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
  /* Clear the DMA Transfer Complete flag */
  DMA_ClearFlag(DMA1_FLAG_TC5);
  /* Program the STOP */
  I2C2->CR1 |= CR1_STOP_Set;
  /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
  while ((I2C2->CR1&0x200) == 0x200);  
}

int I2C2_RxDone(void)
{
  /* Wait until DMA end of transfer */
  if(!DMA_GetFlagStatus(DMA1_FLAG_TC5)) return 0;
  ForecStop();
#if 0
  /* Disable DMA Channel */
  DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
  /* Clear the DMA Transfer Complete flag */
  DMA_ClearFlag(DMA1_FLAG_TC5);
  /* Program the STOP */
  I2C2->CR1 |= CR1_STOP_Set;
  /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
  while ((I2C2->CR1&0x200) == 0x200); 
#endif  
  return 1;
}


/**
  * @brief  Writes buffer of bytes.
  * @param pBuffer: Buffer of bytes to be sent to the slave.
  * @param NumByteToWrite: Number of bytes to be sent by the Master.
  * @param Mode: Polling or DMA or Interrupt having the highest priority in the application.
  * @param SlaveAddress: The address of the slave to be addressed by the Master.
  * @retval : None.
  */
Status I2C2_Master_BufferWrite(uint8_t* pBuffer,  uint32_t NumByteToWrite, uint8_t SlaveAddress )
{
  if(I2C2_Master_BufferWrite_Init(pBuffer,NumByteToWrite,SlaveAddress) != Success) return Error ;
  while(!I2C2_TxDone()) Yield();
  return Success;
}

Status I2C2_Master_BufferWrite_Init(uint8_t* pBuffer,  uint32_t NumByteToWrite, uint8_t SlaveAddress )

{

    __IO uint32_t temp = 0;
    __IO uint32_t Timeout = 0;

    /* Enable Error IT (used in all modes: DMA, Polling and Interrupts */
    I2C2->CR2 |= I2C_IT_ERR;
    Timeout = I2C2_TMO;
    /* Configure the DMA channel for I2Cx transmission */
    I2C2_DMAConfig ( pBuffer, NumByteToWrite, I2C_DIRECTION_TX);
    /* Enable the I2Cx DMA requests */
    I2C2->CR2 |= CR2_DMAEN_Set;
    /* Send START condition */
    I2C2->CR1 |= CR1_START_Set;
    /* Wait until SB flag is set: EV5 */
    while ((I2C2->SR1&0x0001) != 0x0001)
    {
          if (Timeout-- == 0){
                ForecStop();
                return Error;
          }
    }
    Timeout = I2C2_TMO;
    /* Send slave address */
    /* Reset the address bit0 for write */
    // SlaveAddress &= OAR1_ADD0_Reset;
    Address = (SlaveAddress<<1);
    /* Send the slave address */
    I2C2->DR = Address;
    /* Wait until ADDR is set: EV6 */
    while ((I2C2->SR1&0x0002) != 0x0002)
    {
      if((I2C2->SR1 & (1<<10))||(Timeout-- == 0)){
            I2C2->SR1 &= ~(1<<10);
            ForecStop();
            return Error;
      }
    }

    /* Clear ADDR flag by reading SR2 register */
    temp = I2C2->SR2;
    return Success;
}

int I2C2_TxDone(void)
{
    /* Wait until DMA end of transfer */
    if(DMA_GetFlagStatus(DMA1_FLAG_TC4) == 0) return 0;
    /* Disable the DMA1 Channel 4 */
    DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
    /* Clear the DMA Transfer complete flag */
    DMA_ClearFlag(DMA1_FLAG_TC4);
    /* EV8_2: Wait until BTF is set before programming the STOP */
    while ((I2C2->SR1 & 0x00004) != 0x000004);
    /* Program the STOP */
    I2C2->CR1 |= CR1_STOP_Set;
    /* Make sure that the STOP bit is cleared by Hardware */
    while ((I2C2->CR1&0x200) == 0x200);
    return 1;  
}

/**
  * @brief Prepares the I2Cx slave for transmission.
  * @param I2Cx: I2C1 or I2C2.
  * @param Mode: DMA or Interrupt having the highest priority in the application.
  * @retval : None.
  */

#if 0
void I2C_Slave_BufferReadWrite(I2C_TypeDef* I2Cx,I2C_ProgrammingModel Mode)

{
    /* Enable Event IT needed for ADDR and STOPF events ITs */
    I2Cx->CR2 |= I2C_IT_EVT ;
    /* Enable Error IT */
    I2Cx->CR2 |= I2C_IT_ERR;

    if (Mode == DMA)  /* I2Cx Slave Transmission using DMA */
    {
        /* Enable I2Cx DMA requests */
        I2Cx->CR2 |= CR2_DMAEN_Set;
    }

    else  /* I2Cx Slave Transmission using Interrupt with highest priority in the application */
    {
        /* Enable Buffer IT (TXE and RXNE ITs) */
        I2Cx->CR2 |= I2C_IT_BUF;

    }

}
#endif
/**
* @brief  Initializes peripherals: I2Cx, GPIO, DMA channels .
  * @param  None
  * @retval None
  */
#if 0
void I2C_LowLevel_Init(I2C_TypeDef* I2Cx)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    I2C_InitTypeDef  I2C_InitStructure;

    /* GPIOB clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable the DMA1 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    if (I2Cx == I2C1)
    {
        /* I2C1 clock enable */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
        /* I2C1 SDA and SCL configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        /* Enable I2C1 reset state */
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
        /* Release I2C1 from reset state */
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
    }

    else /* I2Cx = I2C2 */

    {

        /* I2C2 clock enable */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        /* I2C1 SDA and SCL configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        /* Enable I2C2 reset state */
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, ENABLE);
        /* Release I2C2 from reset state */
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, DISABLE);
    }

    /* I2C1 and I2C2 configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = OwnAddress1;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
    I2C_Init(I2C1, &I2C_InitStructure);
    I2C_InitStructure.I2C_OwnAddress1 = OwnAddress2;
    I2C_Init(I2C2, &I2C_InitStructure);

    if (I2Cx == I2C1)

    {   /* I2C1 TX DMA Channel configuration */
        DMA_DeInit(I2C1_DMA_CHANNEL_TX);
        I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0;   /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;    /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF;            /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
        I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);

        /* I2C1 RX DMA Channel configuration */
        DMA_DeInit(I2C1_DMA_CHANNEL_RX);
        DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
    }

    else /* I2Cx = I2C2 */

    {
        /* I2C2 TX DMA Channel configuration */
        DMA_DeInit(I2C2_DMA_CHANNEL_TX);
        I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0;   /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;    /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF;            /* This parameter will be configured durig communication */
        I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
        I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);

        /* I2C2 RX DMA Channel configuration */
        DMA_DeInit(I2C2_DMA_CHANNEL_RX);
        DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);

    }
}
#endif

void I2C2_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    I2C_InitTypeDef  I2C_InitStructure;

    /* GPIOB clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable the DMA1 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    /* I2C2 clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    /* I2C1 SDA and SCL configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Enable I2C2 reset state */
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, ENABLE);
    /* Release I2C2 from reset state */
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2, DISABLE);

    /* I2C1 and I2C2 configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = OwnAddress1;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
    I2C_InitStructure.I2C_OwnAddress1 = OwnAddress2;
    I2C_Init(I2C2, &I2C_InitStructure);

    /* I2C2 TX DMA Channel configuration */
    DMA_DeInit(I2C2_DMA_CHANNEL_TX);
    I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
    I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0;   /* This parameter will be configured durig communication */
    I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;    /* This parameter will be configured durig communication */
    I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF;            /* This parameter will be configured durig communication */
    I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);

    /* I2C2 RX DMA Channel configuration */
    DMA_DeInit(I2C2_DMA_CHANNEL_RX);
    DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
    FreeI2C2();
}
/**
  * @brief  Initializes DMA channel used by the I2C Write/read routines.
  * @param  None.
  * @retval None.
  */

#if 0
void I2C_DMAConfig(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t BufferSize, uint32_t Direction)
{
    /* Initialize the DMA with the new parameters */
    if (Direction == I2C_DIRECTION_TX)
    {
        /* Configure the DMA Tx Channel with the buffer address and the buffer size */
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)BufferSize;

        if (I2Cx == I2C1)
        {
            I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
            DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
            DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
            DMA_Cmd(I2C1_DMA_CHANNEL_TX, ENABLE);
        }
        else
        {
            I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
            DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
            DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
            DMA_Cmd(I2C2_DMA_CHANNEL_TX, ENABLE);
        }
    }
    else /* Reception */
    {
        /* Configure the DMA Rx Channel with the buffer address and the buffer size */
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)BufferSize;
        if (I2Cx == I2C1)
        {

            I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
            DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
            DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
            DMA_Cmd(I2C1_DMA_CHANNEL_RX, ENABLE);
        }

        else
        {
            I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
            DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
            DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
            DMA_Cmd(I2C2_DMA_CHANNEL_RX, ENABLE);
        }

    }
}

#endif

void I2C2_DMAConfig(uint8_t* pBuffer, uint32_t BufferSize, uint32_t Direction)
{
    /* Initialize the DMA with the new parameters */
    if (Direction == I2C_DIRECTION_TX)
    {
        /* Configure the DMA Tx Channel with the buffer address and the buffer size */
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)BufferSize;

        I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
        DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
        DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
        DMA_Cmd(I2C2_DMA_CHANNEL_TX, ENABLE);
    }
    else /* Reception */
    {
        /* Configure the DMA Rx Channel with the buffer address and the buffer size */
        I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
        I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)BufferSize;
        I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
        DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
        DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
        DMA_Cmd(I2C2_DMA_CHANNEL_RX, ENABLE);
    }
}


/**
  * @}
  */

Status I2C2_Read_Registers(uint8_t SlaveAddress,uint8_t RegisterNo,uint8_t* pRegisterBuf,  uint32_t NumByteToRead){
  if(I2C2_Master_BufferWrite(&RegisterNo,  1, SlaveAddress)!= Success) return Error;
  return I2C2_Master_BufferRead(pRegisterBuf, NumByteToRead, SlaveAddress);
}

/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

#endif

#if I2C_MODE == I2C_POLLING_MODE

#define    SDA_PIN       GPIO_Pin_11
#define    SCL_PIN       GPIO_Pin_10
#define    SDA_HI()      GPIOB->BSRR = SDA_PIN
#define    SDA_IS_HI()   (GPIOB->IDR & SDA_PIN)
#define    I2C2_IS_ACK() (!SDA_IS_HI())
#define    SDA_LO()      GPIOB->BRR = SDA_PIN
#define    SCL_HI()      GPIOB->BSRR = SCL_PIN
#define    SCL_LO()      GPIOB->BRR = SCL_PIN

Status I2C2_Write_Registers(uint8_t SlaveAddress,uint8_t StartRegisterNo,uint8_t* pRegisterBuf,  uint32_t NumByteToRead);
static uint16_t I2C2_Timer;

static void Delay1us(void)
{
  __IO uint32_t i;
  for(i = 5; i != 0; i--)
  {
  }
}

static void I2C2_Start(void)
{
   SDA_LO();
   Delay1us();
   SCL_LO();
   Delay1us();
}

static void I2C2_Stop(void)
{
  SDA_LO();
  Delay1us();
  SCL_HI();
  Delay1us();
  SDA_HI();
}

static void I2C2_ACK(void) // 9'th clk with SDA = 0
{
    SDA_LO();  // send ACK
    Delay1us();
    SCL_HI();
    Delay1us();
    SCL_LO();
    SDA_HI();    
    Delay1us();
}

static void I2C2_NAK(void) // 9'th clk with SDA = 1
{
    SCL_HI();
    Delay1us();
    SCL_LO();
    Delay1us();    
}

static void I2C2_Byte_Tx(uint8_t ByteData)
{
  for(int i=0;i<8;i++){  // send address
    (ByteData & 0x80) ? SDA_HI(): SDA_LO();
    ByteData <<= 1;
    Delay1us();
    SCL_HI();
    Delay1us();
    SCL_LO();
  }
  Delay1us();
}

static uint8_t I2C2_Byte_Rx(void)
{
  uint8_t ByteData;
  
  for(int i=0;i<8;i++){  // send address
    Delay1us();    
    ByteData <<= 1;
    SCL_HI();    
    if(SDA_IS_HI()) ByteData++;
    Delay1us();
    SCL_LO();
  }
  Delay1us();
  return ByteData;
}

static int I2C2_Send_Address(uint8_t SlaveAddress)
{
  I2C2_Byte_Tx(SlaveAddress);    // send Address
  SDA_HI();
  Delay1us();  // wait for ack
  if(!I2C2_IS_ACK()){ // not ack yet
    I2C2_Timer = SetTimer(2); // 2ms time out
    do {
      Yield();
      if(ChkTimer(I2C2_Timer) == 0){ // time out
        SCL_LO();
        Delay1us();
        SCL_HI();
        Delay1us();
        SDA_HI();
        return Error;
      }
    } while (!I2C2_IS_ACK());    
  }
  return Success;
}

Status I2C2_Read_Registers(uint8_t SlaveAddress,uint8_t StartRegisterNo,uint8_t* pRegisterBuf,  uint32_t NumByteToRead){
  // send slave address
  SlaveAddress <<= 1 ;     // wriite operation
  I2C2_Start();
  if(I2C2_Send_Address(SlaveAddress) == Error) {
    I2C2_NAK();
    I2C2_Stop();
    return Error;
  }
  I2C2_NAK();
  // send register No.
  I2C2_Byte_Tx(StartRegisterNo);
  if(SDA_IS_HI()){ // NAK
    I2C2_NAK();
    I2C2_Stop();
    return Error;
  }
  I2C2_NAK();
  I2C2_Stop();
  Delay1us();
  // Send Address again
  I2C2_Start();
  if(I2C2_Send_Address(SlaveAddress|1) == Error) { // read operation
    I2C2_NAK();
    I2C2_Stop();
    return Error;
  }
  I2C2_NAK();  
  // read data
  for(;NumByteToRead;NumByteToRead--){
    *pRegisterBuf++ = I2C2_Byte_Rx();
    if(NumByteToRead != 1) I2C2_ACK(); 
    else I2C2_NAK();
  }
  I2C2_Stop();
  return Success;
}

Status I2C2_Write_Registers(uint8_t SlaveAddress,uint8_t StartRegisterNo,uint8_t* pRegisterBuf,  uint32_t NumByteToWrite){

  // send slave address
  SlaveAddress <<= 1 ;     // wriite operation
  I2C2_Start();
  if(I2C2_Send_Address(SlaveAddress) == Error) {
    I2C2_NAK();
    I2C2_Stop();
    return Error;
  }
  I2C2_NAK();
  // send register No.
  I2C2_Byte_Tx(StartRegisterNo);
  if(SDA_IS_HI()){ // NAK
    I2C2_NAK();
    I2C2_Stop();
    return Error;
  }
  I2C2_NAK();
  // send data
  for(;NumByteToWrite;NumByteToWrite--){
    I2C2_Byte_Tx(*pRegisterBuf++);
    if(SDA_IS_HI()){ // receive NAK
      I2C2_NAK();
      I2C2_Stop();
      return Error;
    }
    I2C2_NAK();  
  }
  I2C2_Stop();
  return Success;
}

Status I2C2_Master_BufferWrite(uint8_t* pBuffer,  uint32_t NumByteToWrite, uint8_t SlaveAddress)
{
  if(NumByteToWrite<2) return Error;
  return I2C2_Write_Registers(SlaveAddress,*pBuffer,pBuffer+1, NumByteToWrite-1);
}

void I2C2_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    /*  SDA , SCL  configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_10|GPIO_Pin_11);
    FreeI2C2();
}


#endif